/**
 * @file log_flash.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2024-12-16
 * 
 * @copyright Copyright (c) 2024
 * 
 */
#include "log_flash.h"
 sys_ram_t		 SysRam			= {0};
 sys_log_param_t 	 SysLogParam	= {0};
 log_flash_ops_def g_log_flash_ops= {0};

#define SET_LOG_LEVEL(LEVEL)		( SysRam.system_print_level = LEVEL )
#define GET_LOG_LEVEL()				( SysRam.system_print_level )
 
/* 打印格式 */
system_print_fmt_t system_print_fmt_list[] = {
	{ .level = LOG_ERROR_LEVEL,   .fmt_str = "<error>:"},
	{ .level = LOG_WARN_LEVEL,    .fmt_str = "<warn>:"},
	{ .level = LOG_INFO_LEVEL,    .fmt_str = "<info>:"},
	{ .level = LOG_DEBUG_LEVEL,   .fmt_str = "<debug>:"},
	{ .level = LOG_RECORD_LEVEL,  .fmt_str = "<record>:"},
};

/* 定义一个结构体Time*/
static flash_time_t Time =	
{
	.Year	= 1970,
	.Month	= 1,
	.Day	= 1,
	.Hour	= 0,
	.Minute	= 0,
	.Second	= 0,
	.Ms		= 0
};

#ifdef LOG_FLASH_USING_HOOK
static void (*log_flash_hook)(void* user_data) = NULL;
/**
 * @brief set hook function
 * 
 * @param hook function pointer
 * @version 0.1
 * @author your name (you@domain.com)
 * @date 2024-12-16
 * @copyright Copyright (c) 2024
 */
void log_flash_inited_sethook(void (*hook)(void* user_data))
{
    log_flash_hook = hook;
}
#endif /* defined(LOG_FLASH_USING_HOOK) */

/**
 * @brief ms to time
 * 
 * @param s_ms ms 
 * @return flash_time_t* type handle
 * @version 0.1
 * @author your name (you@domain.com)
 * @date 2024-12-16
 * @copyright Copyright (c) 2024
 */
flash_time_t* log_flash_MsToTime(uint32_t s_ms)
{
	flash_time_t* flash_time_p = &Time;
	static uint16_t daycnt = 0;
	uint32_t s_Second = 0;
	uint32_t temp = 0;
	uint16_t temp1 = 0;
	uint8_t mon_table[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; /* 平年的月份日期表 */

	s_Second = s_ms / 1000;
	
	temp = s_Second/DayToSecond;   /* 得到天数(秒数对应的) */
	if(daycnt != temp){	/* 超过一天了 */
		daycnt = temp;
		temp1 = 1970;  /* 从1970年开始 */
		while(temp >= CommonYear){
		     if(((temp1 % 4 == 0) && (temp1 % 100 != 0)) || (temp1 % 400 == 0)){ /* 是闰年 */
			     if(temp >= LeapYear)temp-=LeapYear;/* 闰年的秒钟数 */
			     else break;
		     }
		     else temp-=CommonYear;       /* 平年 */
		     temp1++;
		}
		Time.Year = temp1; /* 得到年份 */
		temp1=0;
		while(temp >= CommonFeb){/* 超过了一个月 */
			if((((Time.Year % 4 == 0) && (Time.Year % 100 != 0)) || (Time.Year % 400 == 0))&&temp1 == 1){ /* 判断当年是不是闰年且是不是2月份 */
				if(temp >= LeapFeb)temp-=LeapFeb;/* 闰年的秒钟数 */
				else break;
			}else{
	            if(temp >= mon_table[temp1])temp-=mon_table[temp1];/* 平年 */
	            else break;
			}
			temp1++;
		}
		Time.Month = temp1+1;/* 得到月份 */
		Time.Day = temp+1;  /* 得到日期 */
	}
	temp = s_Second%DayToSecond;     /* 得到秒数 */
	Time.Hour = temp/HourToSecond;     /* 得到小时数 */
	Time.Minute = (temp%HourToSecond)/MinuteToSecond; /* 得到分钟数 */
	Time.Second = (temp%HourToSecond)%MinuteToSecond; /* 得到秒钟数 */
	Time.Ms = s_ms % 1000; /* 得到毫秒 */
	return flash_time_p;
}

/**
 * @brief Get the log flash table object
 * 
 * @param zone flash zone
 * @return flash_table_t* type handle 
 * @version 0.1
 * @author your name (you@domain.com)
 * @date 2024-12-16
 * @copyright Copyright (c) 2024
 */
static flash_table_t *get_log_flash_table(flash_zone_e zone)
{
	for (int i = 0; i < sizeof(flash_table) / sizeof(flash_table[0]); i++) {
	if (zone == flash_table[i].zone) 
	  return (flash_table_t *)&flash_table[i];
	}
	log_flash_print("flash table is NULL\r\n");
	return NULL;
}

/**
 * @brief flash写数据
 * 
 * @param zone 分区
 * @param address 地址
 * @param data 数据
 * @param length 长度
 * @return int 0：成功 <0：失败
 */
static int log_flash_write(flash_zone_e zone, uint32_t address, uint8_t *data, uint32_t length)
{
	int ret = 0;
	flash_table_t *flash_table_tmp = get_log_flash_table(zone);
	if ( flash_table_tmp == NULL ){
		log_flash_print("flash_table_tmp is NULL\r\n");
		return -1;
	}
	else if ( address < flash_table_tmp->start_address ){
		log_flash_print("address:%x, start_address:%x\r\n", address, flash_table_tmp->start_address);
		return -2;
	}
	else if ( (address + length) > flash_table_tmp->end_address ){
		log_flash_print("address:%x, end_address:%x\r\n", (address + length), flash_table_tmp->end_address);
		return -3;
	}	
	ret = g_log_flash_ops.log_flash_write(data, address, length);
	return ret;
}

/**
 * @brief flash读数据
 * 
 * @param zone 分区
 * @param address 地址
 * @param buffer 数据
 * @param length 长度
 * @return int 0：成功 <0：失败
 */
static int log_flash_read(flash_zone_e zone, uint32_t address, uint8_t*buffer, uint32_t length)
{
	int ret = 0;
	flash_table_t *flash_table_tmp = get_log_flash_table(zone);
	if ( flash_table_tmp == NULL ){
		log_flash_print("flash_table_tmp is NULL\r\n");
		return -1;
	}
	else if ( address < flash_table_tmp->start_address ){
		log_flash_print("address:%x, start_address:%x\r\n", address, flash_table_tmp->start_address);
		return -2;
	}
	else if ( (address + length) > flash_table_tmp->end_address ){
		log_flash_print("address:%x, end_address:%x\r\n", (address + length), flash_table_tmp->end_address);
		return -3;
	}	
	ret = g_log_flash_ops.log_flash_read(buffer, address, length);
	
	return ret;
}

/**
 * @brief log flash erase
 * 
 * @param address 
 * @return int 0：成功 <0：失败
 * @version 0.1
 * @author your name (you@domain.com)
 * @date 2024-12-16
 * @copyright Copyright (c) 2024
 */
static int log_flash_erase(uint32_t address)
{
	int ret = 0;
	ret = g_log_flash_ops.log_flash_erase(address);
	return ret;
}

/**
 * @brief delete all partition
 * 
 * @return int 0：成功 <0：失败 
 * @version 0.1
 * @author your name (you@domain.com)
 * @date 2024-12-16
 * @copyright Copyright (c) 2024
 */
int log_flash_erase_all(void)
{
	int ret = 0;	
	flash_table_t *catalog_table = get_log_flash_table(FLASH_CATALOG_ZONE);
	flash_table_t *para_table    = get_log_flash_table(FLASH_SYSLOG_PARA_ZONE);
	flash_table_t *syslog_table  = get_log_flash_table(FLASH_SYSLOG_ZONE);
	
	if ( catalog_table == NULL || para_table == NULL || syslog_table == NULL){
		log_flash_print("table is NULL\r\n");
		return -1;
	}
	
	for(int i = catalog_table->start_address; i <= catalog_table->end_address; i+= LOG_FLASH_SECTOR_SIZE){
		ret = g_log_flash_ops.log_flash_erase(i / LOG_FLASH_SECTOR_SIZE * LOG_FLASH_SECTOR_SIZE);
		log_flash_print("erase:%08x\r\n", i / LOG_FLASH_SECTOR_SIZE * LOG_FLASH_SECTOR_SIZE);
#ifdef LOG_FLASH_USING_HOOK
		if(log_flash_hook != NULL)
			log_flash_hook(NULL);
#endif /* defined(LOG_FLASH_USING_HOOK) */	
	}
	for(int j = para_table->start_address; j <= para_table->end_address; j+= LOG_FLASH_SECTOR_SIZE){
		ret = g_log_flash_ops.log_flash_erase(j / LOG_FLASH_SECTOR_SIZE * LOG_FLASH_SECTOR_SIZE);
		log_flash_print("erase:%08x\r\n", j / LOG_FLASH_SECTOR_SIZE * LOG_FLASH_SECTOR_SIZE);
#ifdef LOG_FLASH_USING_HOOK
		if(log_flash_hook != NULL)
			log_flash_hook(NULL);
#endif /* defined(LOG_FLASH_USING_HOOK) */	
	}
	for(int k = syslog_table->start_address; k <= syslog_table->end_address; k+= LOG_FLASH_SECTOR_SIZE){
		ret = g_log_flash_ops.log_flash_erase(k / LOG_FLASH_SECTOR_SIZE * LOG_FLASH_SECTOR_SIZE);
		log_flash_print("erase:%08x\r\n", k / LOG_FLASH_SECTOR_SIZE * LOG_FLASH_SECTOR_SIZE);
#ifdef LOG_FLASH_USING_HOOK
		if(log_flash_hook != NULL)
			log_flash_hook(NULL);
#endif /* defined(LOG_FLASH_USING_HOOK) */	
	}
	return ret;
}

/**
 * @brief save the system_log param
 * 
 * @return int 0：成功 <0：失败  
 * @version 0.1
 * @author your name (you@domain.com)
 * @date 2024-12-16
 * @copyright Copyright (c) 2024
 */
static int save_system_log_param(void)
{
	int ret = 0;
	int flag = 0;
	uint32_t break_magic= 0xffffffff;			/* 破坏幻数 */
	uint32_t start_addr = 0;
	uint32_t len 		= sizeof(sys_log_param_t);
	uint8_t *pdata  	= (uint8_t *)&SysLogParam;
	single_sav_t temp_crc_val = {0};//临时保存
	flash_table_t *flash_tmp = get_log_flash_table(FLASH_SYSLOG_PARA_ZONE);
	if ( flash_tmp == NULL ){
		log_flash_print("flash_tmp is NULL\r\n");
		return -1;
	}
	
	start_addr = SysRam.system_log_param_addr;
	
	/* 上一次地址 */
	if ((start_addr + len) > flash_tmp->end_address) { 
		flag = 1;
		start_addr = flash_tmp->end_address - (flash_tmp->end_address - flash_tmp->start_address) % len - len;
	}
	
	/* 先读取上一次的值，防止失败 */
	ret = log_flash_read(FLASH_SYSLOG_PARA_ZONE, start_addr, (uint8_t*)&temp_crc_val, sizeof(single_sav_t));
	if( ret < 0 ){
		log_flash_print("read fail\r\n");
		return ret;
	}
	/* 破坏上一次校验 */
#ifdef USE_FLASH_ERASE
	ret = log_flash_erase(start_addr/LOG_FLASH_SECTOR_SIZE * LOG_FLASH_SECTOR_SIZE);
#else
	ret = log_flash_write(FLASH_SYSLOG_PARA_ZONE, start_addr, (uint8_t*)&break_magic, sizeof(break_magic));
#endif	
	if( ret < 0 ){
		log_flash_print("write fail\r\n");
		return ret;
	}
	
	/* 更新校验值 */
	SysLogParam.crc_val.magic = SYSTEM_LOG_MAGIC_PARAM;
	SysLogParam.crc_val.len   = sizeof(sys_log_param_t) - sizeof(single_sav_t);
	SysLogParam.crc_val.crc   = g_log_flash_ops.log_flash_crc16(&pdata[sizeof(single_sav_t)], SysLogParam.crc_val.len);
	
	if (flag == 1){
		start_addr = flash_tmp->start_address;
	}
	
	/* 记录地址 */
	SysRam.system_log_param_addr = start_addr + len;
	
	/* 写入最新的校验 */
	ret = log_flash_write(FLASH_SYSLOG_PARA_ZONE, start_addr, pdata, len);
	if( ret < 0 ){
		SysLogParam.crc_val.magic = temp_crc_val.magic;
		SysLogParam.crc_val.len   = temp_crc_val.len;
		SysLogParam.crc_val.crc   = temp_crc_val.crc;
		log_flash_print("NEW system_log_param write fail\r\n");
		
		/* 写入旧的的校验 */
		ret = log_flash_write(FLASH_SYSLOG_PARA_ZONE, start_addr, pdata, len);
		if( ret < 0 ){
			log_flash_print("OLD system_log_param write fail\r\n");
		}
	}	
	
	return ret;
}

/**
 * @brief load_system_log_default_param
 * 
 * @return int 0：成功 <0：失败  
 * @version 0.1
 * @author your name (you@domain.com)
 * @date 2024-12-16
 * @copyright Copyright (c) 2024
 */
static int load_system_log_default_param(void)
{
	int ret = 0;
	SysLogParam.system_log.catalog_cyclic_status 	= 0;
	SysLogParam.system_log.catalog_num 				= 0;
	SysLogParam.system_log.log_cyclic_status 		= 0;
	SysLogParam.system_log.log_current_time.Year 	= 1970;
	SysLogParam.system_log.log_current_time.Month 	= 1;
	SysLogParam.system_log.log_current_time.Day 	= 1;
	SysLogParam.system_log.log_current_time.Hour 	= 0;
	SysLogParam.system_log.log_current_time.Minute 	= 0;
	SysLogParam.system_log.log_current_time.Second 	= 0;
	SysLogParam.system_log.write_pos 				= 0;
	SysLogParam.system_catalog.log_addr 			= 0;
	SysLogParam.system_catalog.log_id 				= 0;
	SysLogParam.system_catalog.log_offset			= 0;
	SysLogParam.system_catalog.log_time.Year 		= 1970;
	SysLogParam.system_catalog.log_time.Month 		= 1;
	SysLogParam.system_catalog.log_time.Day 		= 1;
	SysLogParam.system_catalog.log_time.Hour 		= 0;
	SysLogParam.system_catalog.log_time.Minute 		= 0;
	SysLogParam.system_catalog.log_time.Second 		= 0;
	
	flash_table_t *flash_tmp = get_log_flash_table(FLASH_SYSLOG_PARA_ZONE);
	if ( flash_tmp == NULL ){
		log_flash_print("flash_tmp is NULL\r\n");
		return -1;
	}
	
	SysRam.system_log_param_addr 	= flash_tmp->start_address;
	SysRam.system_log_print_enable 	= 1;
	
	ret = save_system_log_param();
	if( ret < 0 ){//成功
		log_flash_print("save param fail\r\n");
	}
	return ret;
}

/**
 * @brief 加载系统日志参数
 * 
 * @return int 0：成功 <0：失败
 * @version 0.1
 * @author your name (you@domain.com)
 * @date 2024-11-18
 * @copyright Copyright (c) 2024
 */
static int load_system_log_param(void)
{
	uint16_t cal_crc = 0;
	uint32_t end_addr = 0;
	uint32_t interal = sizeof(sys_log_param_t);
	uint32_t data_len = interal - sizeof(single_sav_t);
	uint8_t *pram = (uint8_t *)&SysLogParam;
	flash_table_t *flash_tmp = get_log_flash_table(FLASH_SYSLOG_PARA_ZONE);
	if ( flash_tmp == NULL ){
		log_flash_print("flash_tmp is NULL\r\n");
		return -1;
	}
	/* 从后向前遍历 */
	end_addr = flash_tmp->end_address - (flash_tmp->end_address - flash_tmp->start_address) % interal;
	for (uint32_t i = end_addr - interal; i >= flash_tmp->start_address; i -= interal) {
		if(log_flash_read(FLASH_SYSLOG_PARA_ZONE, i, pram, interal) < 0){
			log_flash_print("read system param fail addr: %x, len:%x\r\n", i, interal);
			return -2;
		}
		
		/* 信息校验 */
		if ( (SysLogParam.crc_val.magic == SYSTEM_LOG_MAGIC_PARAM) && 
			 (SysLogParam.crc_val.len == data_len) )
		{
			cal_crc = g_log_flash_ops.log_flash_crc16(&pram[sizeof(single_sav_t)], data_len);
			if (SysLogParam.crc_val.crc == cal_crc) {
				SysRam.system_log_param_addr = i + interal;
				log_flash_print("Load System Log Param Addr[0x%08x]!\r\n", SysRam.system_log_param_addr);
				return 0;
			}
			else{
				log_flash_print("flash_crc:%x cal_crc :%x\r\n",SysLogParam.crc_val.crc,cal_crc);
			}
		}
	}
	
	/* 使用 默认参数 */
	if( load_system_log_default_param() == 0){
		log_flash_print("Load System Log Param Addr(Default)[0x%08x]!\r\n", flash_tmp->start_address);
		return 0;
	}
	else{
		log_flash_print("load system log default param fail\r\n");
		return -3;
	}
}

/**
 * @brief 读取目录信息
 * 
 * @param catalog 目录
 * @param id 目录ID
 * @return int 0：成功 <0：失败 
 * @version 0.1
 * @author your name (you@domain.com)
 * @date 2024-11-18
 * @copyright Copyright (c) 2024
 */
static int system_catalog_read(system_catalog_t *catalog, uint32_t id)
{
	int ret = 0;
	uint32_t addr = 0;
	uint16_t rlen = sizeof(system_catalog_t);
	uint8_t *pbuf = (uint8_t *)catalog;
	flash_table_t *flash_tmp = get_log_flash_table(FLASH_CATALOG_ZONE);
	if ( flash_tmp == NULL ){
		log_flash_print("flash_tmp is NULL\r\n");
		return -1;
	}
	
	addr = flash_tmp->start_address + (rlen * (id));
	if (addr > flash_tmp->end_address) {
		log_flash_print("address:%x, end_address:%x\r\n", addr, flash_tmp->end_address);
		return -3;
	}	

	ret = log_flash_read(FLASH_CATALOG_ZONE, addr, pbuf, rlen);
	if( ret < 0){
		log_flash_print("read fail\r\n");
	}
	return ret;
}

/**
 * @brief 写入目录信息
 * 
 * @param catalog 目录
 * @param id 目录ID
 * @return int 0：成功 <0：失败 
 * @version 0.1
 * @author your name (you@domain.com)
 * @date 2024-11-18
 * @copyright Copyright (c) 2024
 */
static int system_catalog_write(system_catalog_t *catalog, uint32_t id)
{
	int ret = 0;
	uint32_t start_addr = 0;
	uint16_t wlen = sizeof(system_catalog_t);
	uint8_t *pdata = (uint8_t *)catalog;
	flash_table_t *flash_tmp = get_log_flash_table(FLASH_CATALOG_ZONE);
	if ( flash_tmp == NULL ){
		log_flash_print("flash_tmp is NULL\r\n");
		return -1;
	}
	
	start_addr = flash_tmp->start_address + wlen * (id);
	if ((start_addr + wlen) > flash_tmp->end_address) {
		start_addr = flash_tmp->start_address;
#ifdef USE_FLASH_ERASE
		for(int i = 0; i < (flash_tmp->end_address - flash_tmp->start_address) / LOG_FLASH_SECTOR_SIZE; i++){
			ret = log_flash_erase(i * LOG_FLASH_SECTOR_SIZE);
			if( ret < 0){
				log_flash_print("erase error:%x\r\n",i * LOG_FLASH_SECTOR_SIZE);
				return ret;
			}
		}
#endif	
	}

	ret = log_flash_write(FLASH_CATALOG_ZONE, start_addr, pdata, wlen);
	if( ret < 0){
		log_flash_print("write fail\r\n");
	}
	return ret;
}

/**
 * @brief 打印所有的目录
 * 
 * @return int 0：成功 <0：失败  
 * @version 0.1
 * @author your name (you@domain.com)
 * @date 2024-11-21
 * @copyright Copyright (c) 2024
 */
int system_catalog_all_print(void)
{
	system_catalog_t catalog = {0};
	
	log_flash_print("LOG_ID		LOG_DATE		LOG_ADDR		LOG_OFFSET	\r\n");
	for (int i = 0; i <= SysLogParam.system_log.catalog_num; i++) {
		if (i == (SysLogParam.system_catalog.log_id)) {
			catalog = SysLogParam.system_catalog; /*  */
		} 
		else {
			if (system_catalog_read(&catalog, i) < 0){
				log_flash_print("system_catalog read fail\r\n");
				return -1;
			}
		}
		log_flash_print("%d		%04d-%02d-%02d		0x%08X		0x%08X	\r\n", 
						catalog.log_id, catalog.log_time.Year, catalog.log_time.Month, catalog.log_time.Day, 
						catalog.log_addr, catalog.log_offset);
		memset((char *)&catalog, 0, sizeof(system_catalog_t));
	}
	return 0;
}

/**
 * @brief 读取系统日志任务
 * 
 * @param argc 
 * @return int 0：成功 <0：失败   
 * @version 0.1
 * @author your name (you@domain.com)
 * @date 2024-11-21
 * @copyright Copyright (c) 2024
 */
int system_log_task(uint32_t argc, char **argv) 
{	
	uint32_t lock = 0;
	uint32_t rlen = 0;
	char sector_buf[PRINT_MAX_SIZE] = {0};
	uint32_t offset, start_addr, end_addr;
	system_catalog_t catalog;
#if defined FINSH_USING_MSH
	const char* help_info[] =
    {
		[0]  = "catalog      --- All system log directories are displayed",
		[1]  = "ID number    --- Logs with the specified ID are displayed",
		[2]  = "ALL          --- All ID logs are printed",
    };
	if (argc < 2){
        log_flash_print("Usage:\n");
        for (int i = 0; i < sizeof(help_info) / sizeof(char*); i++)
        {
            log_flash_print("%s\n", help_info[i]);
        }
        log_flash_print("\n");
		
		return 0;
    }
	else{
		const char *operator1 = argv[1];
		const char *operator2 = argv[2];
		if (strcmp(operator1, "catalog") == 0){
			system_catalog_all_print();
			return 0;
		}
		else if (strcmp(operator1, "ALL") == 0){
			SysRam.system_log_print_id = ALL_LOG_PRINT;
		}
		else if (strcmp(operator1, "ID") == 0 && operator2 != NULL){
			SysRam.system_log_print_id = atoi(operator2);
		}
		else 
			return -1;
	}
#else 
	SysRam.system_log_print_id = argc;
	SysRam.system_log_print_enable = 0x01;
#endif /* defined(FINSH_USING_MSH) */
	
	if(g_log_flash_ops.log_flash_lock != NULL)
		lock = g_log_flash_ops.log_flash_lock();
	
	flash_table_t *flash_tmp = get_log_flash_table(FLASH_SYSLOG_ZONE);
	if ( flash_tmp == NULL ){
		log_flash_print("flash_tmp is NULL\r\n");
		if(g_log_flash_ops.log_flash_unlock != NULL)
			g_log_flash_ops.log_flash_unlock(lock);
		return -1;
	}
	
	if (SysRam.system_log_print_id == ALL_LOG_PRINT) {	//所有都打印
		if (0x01 == SysLogParam.system_log.log_cyclic_status) { 
			start_addr 	= flash_tmp->start_address;
			end_addr 	= flash_tmp->end_address;
			offset 		= end_addr - start_addr;		//分区写满offset就为整个分区
		} else {
			start_addr 	= flash_tmp->start_address;
			end_addr 	= start_addr + SysLogParam.system_log.write_pos;
			offset 		= SysLogParam.system_log.write_pos;//分区未写满加pos
		}
	} else { //打印指定ID
		if (SysRam.system_log_print_id == SysLogParam.system_catalog.log_id) {
			catalog = SysLogParam.system_catalog;
		} else {
			if ( system_catalog_read(&catalog, SysRam.system_log_print_id) < 0){
				log_flash_print("system catalog read error\r\n");
			}
		}
		start_addr = catalog.log_addr;
		offset = catalog.log_offset;
	}
	if (0 == offset){
		log_flash_print("offset is 0\r\n");
		if(g_log_flash_ops.log_flash_unlock != NULL)
			g_log_flash_ops.log_flash_unlock(lock);
		return -2;	
	}	
		
	while (1) {
		memset(sector_buf, 0, sizeof(sector_buf));
		rlen = (offset > PRINT_MAX_SIZE - 1) ? PRINT_MAX_SIZE - 1 : offset;
		if (g_log_flash_ops.log_flash_read((uint8_t*)sector_buf, start_addr, rlen) < 0){
			log_flash_print("start_addr:%x rlen:%x\r\n",start_addr,rlen);
			if(g_log_flash_ops.log_flash_unlock != NULL)
				g_log_flash_ops.log_flash_unlock(lock);
			return -3;
		}
		log_flash_print("%s",sector_buf);
#ifdef LOG_FLASH_USING_HOOK
		if(log_flash_hook != NULL)
			log_flash_hook(sector_buf);
#endif /* defined(LOG_FLASH_USING_HOOK) */	
		start_addr += rlen;
		offset -= rlen;
		if (0 == offset) 
			break;
	}
	if(g_log_flash_ops.log_flash_unlock != NULL)
		g_log_flash_ops.log_flash_unlock(lock);
	return 0;
}

#if defined FINSH_USING_MSH

MSH_CMD_EXPORT(system_log_task,system_log_task);
void flash_record(uint32_t argc, char **argv) 
{
	log_flash_record(argv[1]);
}
MSH_CMD_EXPORT(flash_record,flash_record);

#endif
/**
 * @brief 写系统日志
 * 
 * @param wbuf 数据
 * @param wlen 长度
 * @return int 0：成功 <0：失败   
 * @version 0.1
 * @author your name (you@domain.com)
 * @date 2024-11-21
 * @copyright Copyright (c) 2024
 */
int system_log_write(uint8_t *wbuf, int wlen)
{
	int ret = 0;
	uint32_t start_addr = 0;
	uint8_t *pdata = wbuf;
	int system_catalog_max_id;
	
	/* 加载目录分区 */
	flash_table_t *flash_tmp = get_log_flash_table(FLASH_CATALOG_ZONE);
	if ( flash_tmp == NULL ){
		log_flash_print("flash_tmp is NULL\r\n");
		return -1;
	}
	
	/* 最大目录ID */
	system_catalog_max_id = ((flash_tmp->end_address - flash_tmp->start_address) / sizeof(system_catalog_t));
	
	/* 加载日志分区 */
	flash_tmp = get_log_flash_table(FLASH_SYSLOG_ZONE);
	if ( flash_tmp == NULL ){
		log_flash_print("flash_tmp is NULL\r\n");
		return -1;
	}
	start_addr = flash_tmp->start_address + SysLogParam.system_log.write_pos;
	if ((start_addr + wlen) > flash_tmp->end_address) { 
		/* 回到初始地址 */
		start_addr = flash_tmp->start_address;
		/* pos回0 */
		SysLogParam.system_log.write_pos = 0; 
		/* 环写状态1 */		
		SysLogParam.system_log.log_cyclic_status = 0x01;		
	}
	SysLogParam.system_log.write_pos += wlen; 
	
	/* 时间 */
	if ((SysLogParam.system_log.log_current_time.Year != SysLogParam.system_catalog.log_time.Year) ||
		(SysLogParam.system_log.log_current_time.Month != SysLogParam.system_catalog.log_time.Month) ||
		(SysLogParam.system_log.log_current_time.Day != SysLogParam.system_catalog.log_time.Day)) {
		
		/* 更新当前的系统目录 */
		if ( system_catalog_write(&SysLogParam.system_catalog, SysLogParam.system_catalog.log_id) < 0 ){
			log_flash_print("system_catalog write erroe\r\n");
			return -1;
		}
		/* 更新当前的系统目录时间 */
		SysLogParam.system_catalog.log_time = SysLogParam.system_log.log_current_time;
		
		if ((SysLogParam.system_catalog.log_id + 1) >= system_catalog_max_id) {
			 SysLogParam.system_log.catalog_num = system_catalog_max_id; /* 最大 */
			 SysLogParam.system_log.catalog_cyclic_status = 1; /* 环写1 */
		} else {
			if (0 == SysLogParam.system_log.catalog_cyclic_status) {
				SysLogParam.system_log.catalog_num = SysLogParam.system_catalog.log_id + 1; 
			}
		}
		/* 存储最新目录项信息 */
		SysLogParam.system_catalog.log_id 		= (SysLogParam.system_catalog.log_id + 1) % system_catalog_max_id;
		SysLogParam.system_catalog.log_addr		= start_addr;
		SysLogParam.system_catalog.log_offset 	= wlen; 
	} else {
		SysLogParam.system_catalog.log_offset 	+= wlen; 
	}
	
	/* 保存日志 */
#ifdef USE_FLASH_ERASE
	if( ((flash_tmp->start_address + SysLogParam.system_log.write_pos)/LOG_FLASH_SECTOR_SIZE) != (start_addr / LOG_FLASH_SECTOR_SIZE)){
		if(start_addr == flash_tmp->start_address){
			ret = log_flash_erase(start_addr/LOG_FLASH_SECTOR_SIZE * LOG_FLASH_SECTOR_SIZE);
		}
		else{
			ret = log_flash_erase((flash_tmp->start_address + SysLogParam.system_log.write_pos)/LOG_FLASH_SECTOR_SIZE * LOG_FLASH_SECTOR_SIZE);
		}
	}
#endif
	ret = log_flash_write(FLASH_SYSLOG_ZONE, start_addr, pdata, wlen);
	if( ret < 0 ){
		log_flash_print("write fail\r\n");
		return ret;
	}
	
	/* 保存日志参数 */
	ret = save_system_log_param();
	if( ret < 0 ){
		log_flash_print("save fail\r\n");
		return ret;
	}
	
	return 0;
}

/**
 * @brief 打印
 * 
 * @param level 等级
 * @param fmt 日志
 * @param ... 
 * @return int 0：成功 <0：失败   
 * @version 0.1
 * @author your name (you@domain.com)
 * @date 2024-11-22
 * @copyright Copyright (c) 2024
 */
int slog_format(uint8_t level, const char *fmt, ...)
{
    va_list args;
	int ret = 0;
    int num = 0, i = 0, fmt_index = 0;
    int fmt_str_len = 0;
	uint32_t lock = 0;
    char buf[PRINT_MAX_SIZE] = {0};
	flash_time_t time = {0};
	
	if(g_log_flash_ops.log_flash_lock != NULL)
		lock = g_log_flash_ops.log_flash_lock();
	
	for (i = 0; i < sizeof(system_print_fmt_list)/sizeof(system_print_fmt_list[0]); i++) {
		if (level == system_print_fmt_list[i].level) {
			fmt_index = i;
			break;
		}
	}
	if (i >= sizeof(system_print_fmt_list)/sizeof(system_print_fmt_list[0])) {
		goto exit_end;
	}
	
	fmt_str_len = strlen(system_print_fmt_list[fmt_index].fmt_str);
	strncpy((char *)&buf[TIME_PREFIX_SIZE], system_print_fmt_list[fmt_index].fmt_str, fmt_str_len);
	
    va_start(args, fmt);
    num = vsnprintf((char *)&buf[fmt_str_len + TIME_PREFIX_SIZE], PRINT_MAX_SIZE - fmt_str_len - TIME_PREFIX_SIZE - 2, fmt, args);
    va_end(args);
	
    if (num <= 0) {
		goto exit_end;
    }
	
	/* 末尾加\r\n */
	num += fmt_str_len;
	buf[num + TIME_PREFIX_SIZE] = '\r';
	buf[num + TIME_PREFIX_SIZE + 1] = '\n';
	num += 2;
	
	/* 获取时间 */
	if( g_log_flash_ops.log_flash_time != NULL )
		g_log_flash_ops.log_flash_time(&time);
	sprintf(&buf[0], "[%04d-%02d-%02d %02d:%02d:%02d:%03d",time.Year, time.Month, time.Day,time.Hour, time.Minute, time.Second, time.Ms);
	buf[TIME_PREFIX_SIZE - 1] = ']';
	SysLogParam.system_log.log_current_time = time;
	
	if ((LOG_RECORD_LEVEL == level)) 
		system_log_write((uint8_t *)buf, num + TIME_PREFIX_SIZE);
	buf[PRINT_MAX_SIZE - 1] = 0;
	log_flash_print("%s",buf);
#ifdef LOG_FLASH_USING_HOOK
	if(log_flash_hook != NULL)
		log_flash_hook(buf);
#endif /* defined(LOG_FLASH_USING_HOOK) */	
exit_end:
	if(g_log_flash_ops.log_flash_unlock != NULL)
		g_log_flash_ops.log_flash_unlock(lock);
	return ret;
}

/**
 * @brief 初始化
 * 
 * @param log_flash_crc16 CRC16校验
 * @param log_flash_write 写flash
 * @param log_flash_read  读flash
 * @param log_flash_time  时间
 * @param log_flash_lock  上锁
 * @param log_flash_unlock 解锁
 * @return int 0：成功 <0：失败    
 * @version 0.1
 * @author your name (you@domain.com)
 * @date 2024-11-24
 * @copyright Copyright (c) 2024
 */
int log_flash_register( uint16_t (*log_flash_crc16)(uint8_t* puchMsg, uint16_t usDataLen),
						int (*log_flash_write)(uint8_t * _pBuf, uint32_t _uiWriteAddr, uint16_t _usSize),
						int (*log_flash_read)(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize),
						int (*log_flash_erase)(uint32_t erase_addr),
						int (*log_flash_time)(flash_time_t *date),
						uint32_t (*log_flash_lock)(void),
						uint32_t (*log_flash_unlock)(uint32_t level) ){
	int ret = 0;
	if ( log_flash_crc16 == NULL || log_flash_write == NULL || log_flash_read == NULL || log_flash_erase == NULL)			
		return -1;
	
	g_log_flash_ops.log_flash_crc16 = log_flash_crc16;
	g_log_flash_ops.log_flash_write = log_flash_write;
	g_log_flash_ops.log_flash_read  = log_flash_read ;
	g_log_flash_ops.log_flash_erase = log_flash_erase;
	g_log_flash_ops.log_flash_time	= log_flash_time;
	
	flash_table_t *catalog_table = get_log_flash_table(FLASH_CATALOG_ZONE);
	flash_table_t *para_table    = get_log_flash_table(FLASH_SYSLOG_PARA_ZONE);
	flash_table_t *syslog_table  = get_log_flash_table(FLASH_SYSLOG_ZONE);
	
	if ( catalog_table == NULL || para_table == NULL || syslog_table == NULL){
		log_flash_print("table is NULL\r\n");
		return -2;
	}
	
	if( catalog_table->end_address - catalog_table->start_address < sizeof(system_catalog_t) ){
		log_flash_print("catalog_table size must be greater than or equal to 0x%08x\r\n", sizeof(system_catalog_t));
		return -3;
	}
	
	if( para_table->end_address - para_table->start_address < 2*sizeof(sys_log_param_t) ){
		log_flash_print("para_table size must be greater than or equal to 0x%08x\r\n", 2*sizeof(sys_log_param_t));
		return -4;
	}
	
	if( syslog_table->end_address - syslog_table->start_address < PRINT_MAX_SIZE ){
		log_flash_print("syslog_table size must be greater than or equal to 0x%08x\r\n", PRINT_MAX_SIZE);
		return -5;
	}
	
	/* 加载系统日志参数 */
	ret = load_system_log_param();
	
	if (ret == 0 )
		ret = system_catalog_all_print();
	
	return ret;
}
